Appearance
[中文版本](/posts/c教程/zh-CN/05-输入输出与文件/048-Reading Configuration Files)
As your C programs grow, hardcoding settings like file paths, thresholds, or user preferences becomes limiting. Configuration files let your program read settings at runtime, a critical capability for tools, servers, and embedded systems.
You’ll learn how to read and parse configuration files using standard I/O and string handling.
The Goal
A configuration file might look like this:
port=8080
host=localhost
max_clients=100
log_file=server.logYour program should:
- Open the file
- Read it line by line
- Split each line into
keyandvalue - Store or use those values
Step 1. Define a Structure for Config
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE 128
typedef struct {
int port;
char host[64];
int max_clients;
char log_file[64];
} Config;ThisConfig struct will hold parsed values.
Step 2. Implement the Parser
void load_config(const char *filename, Config *cfg) {
FILE *fp = fopen(filename, "r");
if (!fp) {
perror("Cannot open config file");
exit(1);
}
char line[MAX_LINE];
while (fgets(line, sizeof(line), fp)) {
line[strcspn(line, "\n")] = '\0'; // remove newline
if (line[0] == '#' || strlen(line) == 0)
continue; // skip comments and blanks
char key[64], value[64];
if (sscanf(line, "%63[^=]=%63s", key, value) == 2) {
if (strcmp(key, "port") == 0)
cfg->port = atoi(value);
else if (strcmp(key, "host") == 0)
strncpy(cfg->host, value, sizeof(cfg->host));
else if (strcmp(key, "max_clients") == 0)
cfg->max_clients = atoi(value);
else if (strcmp(key, "log_file") == 0)
strncpy(cfg->log_file, value, sizeof(cfg->log_file));
}
}
fclose(fp);
}This function:
- Reads each line
- Ignores comments and empty lines
- Extracts key-value pairs using
sscanf() - Updates fields in
Config
Step 3. Use the Configuration
int main(void) {
Config cfg = {0};
load_config("config.txt", &cfg);
printf("Server settings:\n");
printf("Host: %s\n", cfg.host);
printf("Port: %d\n", cfg.port);
printf("Max clients: %d\n", cfg.max_clients);
printf("Log file: %s\n", cfg.log_file);
return 0;
}Run with aconfig.txt file:
host=127.0.0.1
port=9090
max_clients=250
log_file=/tmp/server.logOutput:
Server settings:
Host: 127.0.0.1
Port: 9090
Max clients: 250
Log file: /tmp/server.logTiny Code: Default Fallbacks
You can initialize sensible defaults before reading the file:
Config cfg = {
.port = 8080,
.host = "localhost",
.max_clients = 100,
.log_file = "server.log"
};This ensures your program still works even if the file is missing some values.
Step 4. Optional: Handle Quoted Values
If you expect values with spaces (likename="My Server"), you can modify parsing logic:
if (sscanf(line, "%63[^=]=\"%63[^\"]\"", key, value) == 2) {
// handle quoted strings
}Step 5. Optional: Generic Storage
For more flexible systems, you can use a hash table or array of key-value pairs instead of fixed fields:
typedef struct {
char key[64];
char value[64];
} KVPair;
KVPair settings[100];This allows loading arbitrary keys without recompiling the program.
Why It Matters
Configuration files let you:
- Separate code from data, no need to recompile to change behavior
- Adapt to environments, dev, test, production
- Make your program reusable by others
They’re used everywhere, from.ini and.conf files to complex YAML/JSON formats in modern systems.
Try It Yourself
- Add support for
#comments and empty lines (skip them safely). - Make the parser print a warning for unknown keys.
- Add a function
save_config()that writes the struct back to a file. - Add
reload_config()to update settings at runtime. - Implement your own
.iniformat parser supporting[section]headers.
With configuration files, your C programs gain flexibility and real-world usability, they can adapt, reload, and persist settings just like professional systems software. Next, you’ll learn how to serialize and deserialize structs to disk, the next level of persistent data handling in Section 49.
